#include "eventloop.hpp"
#include "acceptor.hpp"
#include "tcpconnection.hpp"
namespace moqi
{
using std::runtime_error;

EventLoop::EventLoop(Acceptor & acceptor, int max_events):
_efd(createEpollFd()),
_max_events(max_events),
_isLooping(false),
_acceptor(acceptor)
{

    add(_acceptor.getSockFd());
    _events.resize(max_events);
}

EventLoop::~EventLoop()
{
    if(_efd > 0)
    {
        LOG_INFO("~EventLoop");
        close(_efd);
    }
}

void EventLoop::loop()
{
    _isLooping = true;
    LOG_INFO("loop running");
    while(_isLooping)
    {
        waitEvent();
    }
}

void EventLoop::unloop()
{
    LOG_INFO("loop stop");
    _isLooping = false;
}

void EventLoop::waitEvent(int timeoutMs)
{
    int nready = epoll_wait(_efd, _events.data(), _events.size(), timeoutMs);
    if(nready == -1)
    {
        if(errno == EINTR)
        {
            return ;
        }
        LOG_ERROR("Error in epoll_wait");
        throw runtime_error("Error in epoll_wait");
    }
    else if(nready == 0)
    {
        LOG_INFO("epoll_wait timeout");
    }
    else
    {

        for(int i = 0; i < nready; ++i)
        {
            int fd = _events[i].data.fd;
            if(fd == _acceptor.getSockFd())
            {
                handleNewConnection();//处理新链接
            }
            else
            {
                handleMessage(fd);//处理消息到来
            }
        }
    }
}

void EventLoop::add(int fd, uint32_t Epoll_events)
{
    event_t event;//待监听事件
    memset(&event, 0, sizeof(event));
    event.events = Epoll_events;//默认参数为EPOLLIiN
    event.data.fd = fd;//待监听套接字                        
    if(epoll_ctl(_efd, EPOLL_CTL_ADD, fd, &event) == -1)
    {
        LOG_ERROR("Fail to add fd to epoll"); 
        throw runtime_error("Fail to add fd to epoll");        
    }

}

void EventLoop::del(int fd)
{
    if(epoll_ctl(_efd, EPOLL_CTL_DEL, fd, nullptr) == -1)
    {
        LOG_ERROR("Fail to del fd to epoll");        
        throw runtime_error("Fail to del fd to epoll");        
    }

}

void EventLoop::mod(int fd, uint32_t Epoll_events)
{
    event_t event;//待监听事件
    memset(&event, 0, sizeof(event));
    event.events = Epoll_events;//默认参数为EPOLLIiN
    event.data.fd = fd;//待监听套接字                        
    if(epoll_ctl(_efd, EPOLL_CTL_MOD, fd, &event) == -1)
    {
        LOG_ERROR("Fail to mod fd to epoll");        
        throw runtime_error("Fail to mod fd to epoll");        
    }
}

void EventLoop::handleNewConnection()
{
    int fd = _acceptor.accept();//接收新链接
    add(fd);//将新链接加入监听
    TcpConnectionPtr pconnect(new TcpConnection(fd));//创建TcpConnection智能指针
    pconnect->setAllCallback(_onConnection, _onMessage, _onClose);//为其设置任务处理函数
    _connects.insert(std::make_pair(fd, pconnect));//添加fd和TcpConnection的映射
    pconnect->handleNewConnectionCallback();//Tcpconnection处理新链接
}

void EventLoop::handleMessage(int fd)
{
    auto it = _connects.find(fd);
    if(it != _connects.end())
    {
        if(it->second->isClosed())
        {
            it->second->handleCloseCallback();//TcpConnection的断开处理
            del(fd);//epoll的监听删除处理
            _connects.erase(fd);//fd和tcp映射的删除处理
        }
        else
        {
            it->second->handleMessageCallback();
        }
    }

}

int EventLoop::createEpollFd()
{
    int fd = epoll_create1(0);
    if(fd == -1)
    {
        LOG_ERROR("Failed to create epoll instance");
        throw runtime_error("Failed to create epoll instance");
    }
    return fd;
}

}
